package cn.mysdp.utils;

import cn.mysdp.biz.domain.SdpTemplateWithBLOBs;
import cn.mysdp.biz.dto.response.SdpTemplateQueryResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class JavaBeansUtil {

    private JavaBeansUtil() {
        super();
    }

    public static boolean equals(Long v1, Integer v2) {
        if (v1 == null || v2 == null) {
            return false;
        }
        return v1.equals(Long.valueOf(v2));
    }

    public static boolean equals(Integer v1, Long v2) {
        if (v1 == null || v2 == null) {
            return false;
        }
        return v2.equals(Long.valueOf(v1));
    }

    public static boolean equals(Long v1, Long v2) {
        if (v1 == null || v2 == null) {
            return false;
        }
        return v1.equals(v2);
    }

    public static boolean equals(Integer v1, Integer v2) {
        if (v1 == null || v2 == null) {
            return false;
        }
        return v1.equals(v2);
    }

    public static boolean isDate(String str) {
        if(!StringUtils.hasText(str)) {
            return false;
        }
        str = str.trim();
        if(str.startsWith("'")) {
            str = str.split("'")[1].trim();
        }
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            if(dateFormat.parse(str) != null) {
                return true;
            }
            dateFormat = new SimpleDateFormat("yyyy-M-d");
            if(dateFormat.parse(str) != null) {
                return true;
            }
        }catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }

    public static boolean isDatetime(String str) {
        if(!StringUtils.hasText(str)) {
            return false;
        }
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if(dateFormat.parse(str) != null) {
                return true;
            }
            dateFormat = new SimpleDateFormat("yyyy-M-d H:m:s");
            if(dateFormat.parse(str) != null) {
                return true;
            }
        }catch (Exception ex) {

        }
        return false;
    }

    public static String getJsonString(String str, String name) {
        if(StringUtils.hasText(str)) {
            JSONObject jsonObject = JSON.parseObject(str, Feature.AllowSingleQuotes, Feature.AllowUnQuotedFieldNames);
            if(jsonObject.containsKey(name)) {
                return jsonObject.getString(name);
            }
        }
        return null;
    }

    public static String getAliasTableName(IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate) {
        String name = dynTemplate.getAliasTableName();
        if(StringUtils.hasText(name)) {
            return name;
        }
        name = introspectedTable.getTableConfiguration().getTableName();
        return name;
    }

    public static String getAjaxString(String inputString) {
        String str = getCamelCaseString(inputString, false);
        StringBuilder sb = new StringBuilder();

        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    sb.append("_");
                }
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();

    }

    public static String getCamelCaseString(String inputString,
            boolean firstCharacterUppercase) {
        StringBuilder sb = new StringBuilder();

        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);

            switch (c) {
            case '_':
            case '-':
            case '@':
            case '$':
            case '#':
            case ' ':
            case '/':
            case '&':
                if (sb.length() > 0) {
                    nextUpperCase = true;
                }
                break;

            default:
                if (nextUpperCase) {
                    sb.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    sb.append(Character.toLowerCase(c));
                }
                break;
            }
        }

        if (firstCharacterUppercase) {
            sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
        }

        return sb.toString();
    }

    public static String getJSONStringWithoutSubClass(Object obj) {
        JSONObject j = new JSONObject();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field: fields) {
            try {
                if (field.isAnnotationPresent(JSONField.class)) {
                    JSONField f = field.getAnnotation(JSONField.class);
                    field.setAccessible(true);
                    Object v = field.get(obj);
                    if(v != null && !"".equals(v)) {
                        String name = f.name();
                        if (!StringUtils.hasText(name)) {
                            name = field.getName();
                        }
                        if (v instanceof Date && StringUtils.hasText(f.format())) {
                            SimpleDateFormat format = new SimpleDateFormat(f.format());
                            v = format.format(v);
                        }
                        j.put(name, v);
                    }
                }
            }catch (Exception ex) {
                log.info("exception:{}", ex.getMessage(), ex);

            }
        }
        return toJSONString(j);
    }

    public static boolean equals(Object a, Object b) {
        return equals(a, b, false);
    }
    public static boolean equals(Object a, Object b, boolean ignoreNull) {
        if (a == null && b == null) {
            return true;
        }
        if (a == null) {
            a = b;
            b = null;
        }
        if (b == null) {
            if (ignoreNull) {
                if ("".equals(a)) {
                    return true;
                }
                if (JavaBeansUtil.equals(0, a)) {
                    return true;
                }
                if (a instanceof BigDecimal) {
                    if (((BigDecimal) a).compareTo(BigDecimal.ZERO) == 0) {
                        return true;
                    }
                }
            }
            return false;
        }
        if (a instanceof BigDecimal && b instanceof BigDecimal) {
            boolean ret = ((BigDecimal) a).compareTo((BigDecimal)b) == 0;
            if (ret) {
                return true;
            }
            return false;
        }
        if (a.equals(b)) {
            return true;
        }
        return false;
    }

    public static boolean mustHasSettleType(String module) {
        if ("st_shop".equals(module)
                || "st_warehouse".equals(module)
                || "zt_user".equals(module)
                || "zt_dict".equals(module)
                || "sys_error".equals(module)
                || "op_history".equals(module)
                || "base_import".equals(module)
                || "auth_v1".equals(module)
        ) {
            return false;
        }
        return true;
    }

    public static void checkResult(Object result, String module, String method) throws Exception {
        if (JavaBeansUtil.mustHasSettleType(module)) {
            Field field = getField(result.getClass(), "settle_type");
            if (field != null) {
                try {
                    String settleType = (String) field.get(result);
                    if (settleType == null) {
                        field.setAccessible(true);
                        field.set(result, "液态");
                    } else {
                        if (!"气态".equals(settleType)
                                && !"液态".equals(settleType)
                        ) {
                            throw new Exception("settle_type非法："+ module+","+method+","+ settleType+","+JavaBeansUtil.getJSONStringWithoutSubClass(result));
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        Field field = getField(result.getClass(), "if_check_address_match");
        if (field != null) {
            try {
                Integer v = (Integer) field.get(result);
                if (v != null) {
                    if (!JavaBeansUtil.equals(1, v) && !Integer.valueOf(2).equals(v)) {
                        throw new Exception("if_check_address_match非法："+ v+","+JavaBeansUtil.getJSONStringWithoutSubClass(result));
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        if ("st_config".equals(module)) {
            if (!"update".equals(method)) {
                field = getField(result.getClass(), "default_address_province");
                Field field2 = getField(result.getClass(), "default_address_city");
                if (field != null || field2 != null) {
                    try {
                        String v = (String) field.get(result);
                        String v2 = (String) field2.get(result);
                        if (StringUtils.hasText(v) && !StringUtils.hasText(v2)
                                || !StringUtils.hasText(v) && StringUtils.hasText(v2)
                        ) {
                            throw new Exception("default_address_province/default_address_city必须同时设置:"+ JavaBeansUtil.getJSONStringWithoutSubClass(result));
                        }
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static Field getField(Class clz, String name) {
        return getField(clz, name, true);
    }

    public static Field getField(Class clz, String name, Boolean findSuper) {
        String camelCaseName = JavaBeansUtil.getCamelCaseString(name, false);
        while(clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for(Field field: fields) {
                if (name.equals(field.getName())
                        || camelCaseName.equals(field.getName())
                ) {
                    field.setAccessible(true);
                    return field;
                }
                if (field.isAnnotationPresent(JSONField.class)) {
                    JSONField f = field.getAnnotation(JSONField.class);
                    if (StringUtils.hasText(f.name())) {
                        if (name.equals(f.name())
                                || camelCaseName.equals(f.name())
                        ) {
                            field.setAccessible(true);
                            return field;
                        }
                    }
                }
            }
            if (!findSuper) {
                break;
            }
            clz = clz.getSuperclass();
        }
        return null;
    }

    public static Field[] getFields(Class clz) {
        return getFields(clz, true);
    }

    public static Field[] getFields(Class clz, Boolean findSuper) {
        List<Field> fieldList = new ArrayList<>();
        getFields(clz, findSuper, fieldList);
        Field[] fields = new Field[fieldList.size()];
        for(int i = 0; i < fieldList.size(); i++) {
            Field field = fieldList.get(i);
            fields[i] = field;
        }
        return fields;
    }

    public static void getFields(Class clz, Boolean findSuper, List<Field> fieldList) {
        while(clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for(Field field: fields) {
                if (field.isAnnotationPresent(JSONField.class)) {
                    field.setAccessible(true);
                    fieldList.add(field);
                }
            }
            if (!findSuper) {
                break;
            }
            clz = clz.getSuperclass();
        }
    }

    public static Method getMethod(Class clz, String name) {
        return getMethod(clz, name, true);
    }

    public static Method getMethod(Class clz, String name, Boolean findSuper) {
        String camelCaseName = JavaBeansUtil.getCamelCaseString(name, false);

        while (clz != null) {
            for(Method method: clz.getDeclaredMethods()) {
                if (name.equals(method.getName())) {
                    method.setAccessible(true);
                    return method;
                }
                if (method.isAnnotationPresent(JSONField.class)) {
                    JSONField f = method.getAnnotation(JSONField.class);
                    if (StringUtils.hasText(f.name())) {
                        if (name.equals(f.name())
                                || camelCaseName.equals(f.name())
                        ) {
                            method.setAccessible(true);
                            return method;
                        }
                    }
                }
            }
            if (!findSuper) {
                break;
            }
            clz = clz.getSuperclass();
        }
        return null;
    }


    public static Boolean isExcelHolderKeyType(String keyType) {
        if ("String".equals(keyType)
                || "ConstString".equals(keyType)
                || "Double".equals(keyType)
                || "Integer".equals(keyType)
                || "Date".equals(keyType)
        ) {
            return true;
        }
        return false;
    }

    public static String getExcelHolderKeyType(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        int keyTypeIndex = key.lastIndexOf(":");
        if (keyTypeIndex >= 0) {
            String keyType = key.substring(keyTypeIndex+1).split("\\(")[0];
            if (isExcelHolderKeyType(keyType)) {
                return keyType;
            }
        }
        return "String";
    }

    public static String getExcelHolderKeyTypeExtraInfo(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        int keyTypeIndex = key.lastIndexOf(":");
        if (keyTypeIndex >= 0) {
            String keyType = key.substring(keyTypeIndex+1).split("\\(")[0];
            if (isExcelHolderKeyType(keyType)) {
                String extraInfo = key.substring(keyTypeIndex+1).substring(keyType.length());
                if (StringUtils.hasText(extraInfo) && extraInfo.indexOf("(") >= 0) {
                    extraInfo = extraInfo.split("\\(")[1];
                    if (StringUtils.hasText(extraInfo) && extraInfo.indexOf(")") >= 0) {
                        extraInfo = extraInfo.split("\\)")[0];
                        return extraInfo;
                    }
                }
            }
        }
        return "";
    }

    public static String getExcelHolderKey(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        int keyTypeIndex = key.lastIndexOf(":");
        if (keyTypeIndex >= 0) {
            String keyType = key.substring(keyTypeIndex+1).split("\\(")[0];
            if (isExcelHolderKeyType(keyType)) {
                key = key.substring(0, keyTypeIndex);
            }
        }
        if (key.startsWith("sum:")) {
            key = key.substring("sum:".length());
        } else if (key.startsWith("special:")) {
            key = key.substring("special:".length());
        } else if (key.startsWith("dyn_col:")) {
            key = key.substring("dyn_col:".length());
        }
        return key;
    }

    public static Boolean isExcelHolderMulti(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            return true;
        }
        return false;
    }

    public static Boolean isExcelHolderSum(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        if (key.startsWith("sum:")) {
            return true;
        }
        return false;
    }
    public static Boolean isExcelHolderSpecial(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        if (key.startsWith("special:")) {
            return true;
        }
        return false;
    }
    public static Boolean isExcelHolderDyncCol(String holder) {
        String key = holder.substring(3, holder.length() - 3);
        if (key.startsWith("*")) {
            key = key.substring(1);
        }
        if (key.startsWith("dyn_col:")) {
            return true;
        }
        return false;
    }


    public static void copyBooleanProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (Boolean.class.equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV = sourceField.get(source);
            if (srcV == null) {
                return;
            }
            if ("0".equals(srcV+"")) {
                targetField.set(target, new Boolean(false));
            } else {
                targetField.set(target, new Boolean(true));
            }
        }
    }

    public static List<String> fixStringArray(List<String> list) {
        if (!CollectionUtils.isEmpty(list)
                && list.get(0).startsWith("[")
                && list.get(list.size() - 1).endsWith("]")
        ) {
            try {
                String strs = "";
                for(String str: list) {
                    if (strs.length() > 0) {
                        strs += ",";
                    }
                    strs += str;
                }
                JSONArray jsonArray = JSON.parseArray(strs);
                list = new ArrayList<>();
                for(int i = 0; i < jsonArray.size(); i++) {
                    list.add(jsonArray.getString(i));
                }
            }catch(Exception ex) {
                ex.printStackTrace();
            }
        }
        return list;
    }

    public static void copyIntegerProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (Integer.class.equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV = sourceField.get(source);
            if (srcV == null) {
                return;
            }
            if (Boolean.class.equals(sourceField.getType())) {
                Boolean v = (Boolean) srcV;
                if (v) {
                    targetField.set(target, new Integer(1));
                } else {
                    targetField.set(target, new Integer(0));
                }
            } else if (Byte.class.equals(sourceField.getType())) {
                Byte v = (Byte) srcV;
                targetField.set(target, new Integer(v.intValue()));
            } else if (Long.class.equals(sourceField.getType())) {
                Long v = (Long) srcV;
                targetField.set(target, new Integer(v.intValue()));
            } else {
                targetField.set(target, new Integer(srcV+""));
            }
        }
    }

    public static void copyLongProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (Long.class.equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV = sourceField.get(source);
            if (srcV == null) {
                return;
            }
            if (Boolean.class.equals(sourceField.getType())) {
                Boolean v = (Boolean) srcV;
                if (v) {
                    targetField.set(target, new Long(1));
                } else {
                    targetField.set(target, new Long(0));
                }
            } else if (Byte.class.equals(sourceField.getType())) {
                Byte v = (Byte) srcV;
                targetField.set(target, new Long(v.intValue()));
            } else if (Integer.class.equals(sourceField.getType())) {
                Integer v = (Integer) srcV;
                targetField.set(target, new Long(v.intValue()));
            } else {
                targetField.set(target, new Long(srcV+""));
            }
        }
    }

    public static void copyByteProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (Byte.class.equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV = sourceField.get(source);
            if (srcV == null) {
                return;
            }
            if (Boolean.class.equals(sourceField.getType())) {
                Boolean v = (Boolean) srcV;
                if (v) {
                    targetField.set(target, new Byte((byte)1));
                } else {
                    targetField.set(target, new Byte((byte)0));
                }
            } else if (Integer.class.equals(sourceField.getType())) {
                Integer v = (Integer) srcV;
                targetField.set(target, new Byte(v.byteValue()));
            } else if (Long.class.equals(sourceField.getType())) {
                Long v = (Long) srcV;
                targetField.set(target, new Byte(v.byteValue()));
            } else {
                targetField.set(target, new Byte(srcV+""));
            }
        }
    }

    public static void copyStringProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (String.class.equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV = sourceField.get(source);
            if (srcV == null) {
                return;
            }
            if (Boolean.class.equals(sourceField.getType())) {
                Boolean v = (Boolean) srcV;
                if (v) {
                    targetField.set(target, new String("1"));
                } else {
                    targetField.set(target, new String("0"));
                }
            } else {
                targetField.set(target, toJSONString(srcV));
            }
        }
    }

    public static Object clone(Object v) {
        return clone(v, 0);
    }

    public static Object clone(Object v, int deep) {
        Object destV = null;
        if (v == null) {
            destV = null;
        } else if (v instanceof JSONObject) {
            if (deep > 3) {
                destV = v;
            } else {
                JSONObject srcJSONObject = (JSONObject) v;
                JSONObject destJSONObject = new JSONObject();
                for(String key: srcJSONObject.keySet()) {
                    destJSONObject.put(key, clone(srcJSONObject.get(key), deep + 1));
                }
                destV = destJSONObject;
            }
        } else if (v instanceof TreeMap) {
            if (deep > 3) {
                destV = v;
            } else {
                Map srcJSONObject = (Map) v;
                Map destJSONObject = new TreeMap();
                for(Object key: srcJSONObject.keySet()) {
                    destJSONObject.put(key, clone(srcJSONObject.get(key), deep + 1));
                }
                destV = destJSONObject;
            }
        } else if (v instanceof HashMap) {
            if (deep > 3) {
                destV = v;
            } else {
                Map srcJSONObject = (Map) v;
                Map destJSONObject = new HashMap();
                for(Object key: srcJSONObject.keySet()) {
                    destJSONObject.put(key, clone(srcJSONObject.get(key), deep + 1));
                }
                destV = destJSONObject;
            }
        } else if (v instanceof JSONArray) {
            if (deep > 3) {
                destV = v;
            } else {
                JSONArray srcJSONArray = (JSONArray) v;
                JSONArray destJSONArray = new JSONArray();
                for(int i = 0; i < srcJSONArray.size(); i++) {
                    destJSONArray.add(clone(srcJSONArray.get(i), deep + 1));
                }
                destV = destJSONArray;
            }
        } else if (v instanceof ArrayList) {
            if (deep > 3) {
                destV = v;
            } else {
                List srcJSONArray = (List) v;
                List destJSONArray = new ArrayList();
                for(int i = 0; i < srcJSONArray.size(); i++) {
                    destJSONArray.add(clone(srcJSONArray.get(i), deep + 1));
                }
                destV = destJSONArray;
            }
        } else if (v instanceof Boolean) {
            destV = new Boolean((Boolean)v);
        } else if (v instanceof Byte) {
            destV = new Byte((Byte) v);
        } else if (v instanceof Integer) {
            destV = new Integer((Integer) v);
        } else if (v instanceof Long) {
            destV = new Long((Long) v);
        } else if (v instanceof String) {
            destV = new String((String) v);
        } else {
            destV = v;
        }
        return destV;
    }

    public static void copyCollectionProperty(Object source, Object target, Field sourceField, Field targetField) throws Exception {
        if (source == null || target == null || sourceField == null || targetField == null) {
            return;
        }
        if (!targetField.getType().equals(sourceField.getType())) {
            return;
        }
        if (sourceField != null) {
            Object srcV =  sourceField.get(source);
            if (srcV == null) {
                return;
            }
            targetField.set(target, clone(srcV));
        }
    }

    public static void copyProperties(Object source, Object target) throws Exception {
        if (source == null || target == null) {
            return;
        }
        copyProperties(source, target, null, null);
    }

    public static void copyProperties(Object source, Object target, Map<String, Field> sourceFieldSet, Map<String, Field> targetFieldSet) throws Exception {
        if (source == null || target == null) {
            return;
        }
        BeanUtils.copyProperties(source, target);
        Field[] fields = getFields(target.getClass(), true);
        for(Field field: fields) {
            if (Boolean.class.equals(field.getType())) {
                copyBooleanProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
            if (Byte.class.equals(field.getType())) {
                copyByteProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
            if (Integer.class.equals(field.getType())) {
                copyIntegerProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
            if (Long.class.equals(field.getType())) {
                copyLongProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
            if (String.class.equals(field.getType())) {
                copyStringProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
            if (JSONObject.class.equals(field.getType())
                    || TreeMap.class.equals(field.getType())
                    || HashMap.class.equals(field.getType())
                    || JSONArray.class.equals(field.getType())
                    || ArrayList.class.equals(field.getType())
            ) {
                copyCollectionProperty(source, target, getField(source.getClass(), field.getName()), field);
            }
        }
    }

    public static void fixParameters(HttpServletRequest httpServletRequest, Class baseRequestClass) {
        String url = httpServletRequest.getRequestURL().toString();

        //force parse parameter first!
        if (httpServletRequest.getParameterNames() != null) {
            try {
                Map<String, Field> fieldMap = new HashMap<>();
                try {
                    Field[] fields = baseRequestClass.getDeclaredFields();
                    for(Field field: fields) {
                        try {
                            String name = field.getName();
                            if (field.isAnnotationPresent(JsonProperty.class)) {
                                JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
                                if (StringUtils.hasText(jsonProperty.value())) {
                                    name = jsonProperty.value();
                                }
                            } else if (field.isAnnotationPresent(JSONField.class)) {
                                JSONField jsonField = field.getAnnotation(JSONField.class);
                                if (StringUtils.hasText(jsonField.name())) {
                                    name = jsonField.name();
                                }
                            }
                            if (!fieldMap.containsKey(name)) {
                                field.setAccessible(true);
                                fieldMap.put(name, field);
                            }
                        }catch (Exception ex) {

                        }
                    }
                }catch(Exception ex) {

                }

                Object target = httpServletRequest;
                Field hField = JavaBeansUtil.getField(httpServletRequest.getClass(), "request");
                if (hField != null) {
                    target = hField.get(target);
                    hField = null;
                    if (target != null) {
                        hField = JavaBeansUtil.getField(target.getClass(), "coyoteRequest");
                    }
                }
                if (hField != null) {
                    target = hField.get(target);
                    hField = null;
                    if (target != null) {
                        hField = JavaBeansUtil.getField(target.getClass(), "parameters");
                    }
                }
                if (hField != null) {
                    target = hField.get(target);
                    hField = null;
                    if (target != null) {
                        hField = JavaBeansUtil.getField(target.getClass(), "paramHashValues");
                    }
                }
                if (hField != null) {
                    target = hField.get(target);
                    if (target != null) {
                        Map<String, ArrayList<String>> paramHashValues = (Map<String, ArrayList<String>>) target;
                        Map<String, String> newParamHashValues = new HashMap<>();

                        for(String key: new String[]{}) {
                            //删除无效的参数。例如xxx接口同时传递了member_code和memberCode，其中一个有数据，另外一个无数据
                            paramHashValues.remove(key);
                        }

                        for(String key: paramHashValues.keySet()) {
                            String ajaxKey = JavaBeansUtil.getAjaxString(key);
                            String camelKey = JavaBeansUtil.getCamelCaseString(ajaxKey, false);
                            Field field = fieldMap.get(key);
                            if (!key.equals(ajaxKey) && fieldMap.containsKey(ajaxKey)) {
                                if(!newParamHashValues.containsKey(ajaxKey)) {
                                    newParamHashValues.put(ajaxKey, key);
                                }
                                field = fieldMap.get(ajaxKey);
                            }
                            if (!key.equals(camelKey) && fieldMap.containsKey(camelKey)) {
                                if (!newParamHashValues.containsKey(camelKey)) {
                                    newParamHashValues.put(camelKey, key);
                                }
                                field = fieldMap.get(camelKey);
                            }
                            if (field == null) {
                                log.error("miss parameter: "+key+" for class: "+baseRequestClass.getName());
                                continue;
                            }
                            if (!newParamHashValues.containsKey(field.getName())) {
                                newParamHashValues.put(field.getName(), key);
                            }

                            ArrayList<String> values = paramHashValues.get(key);
                            if (!CollectionUtils.isEmpty(values) && values.size() == 1) {
                                String value = values.get(0);
                                if (Byte.class.equals(field.getType())) {
                                    if ("true".equals(value)) {
                                        values.remove(0);
                                        values.add("1");
                                    } else if ("false".equals(value)) {
                                        values.remove(0);
                                        values.add("0");
                                    }
                                } else if (List.class.equals(field.getType())) {
                                    if ("java.util.List<java.lang.String>".equals(field.getGenericType().getTypeName())) {
                                    }
                                }
                            }
                        }
                        for(String key: newParamHashValues.keySet()) {
                            paramHashValues.put(key, paramHashValues.get(newParamHashValues.get(key)));
                        }

                    }
                }

            }catch(Exception ex) {
                ex.printStackTrace();
            }

            log.info("request url: {}, param: {}", url, toJSONString(httpServletRequest.getParameterMap()));

        }


    }

    public static String getSimpleType(String a) {
        return a.replaceAll("java\\.lang\\.", "").replaceAll("java\\.util\\.", "");
    }
    public static boolean isSameType(String a, String b) {
        if(a.equals(b)) {
            return true;
        }
        return getSimpleType(a).equals(getSimpleType(b));
    }

    public static void copyAopProperties(Object src, Object dest) {
        Class clz = src.getClass();
        while(clz != null) {
            Field[] fields = clz.getDeclaredFields();
            for(Field field: fields) {
                try {
                    int mod = field.getModifiers();
                    if (!field.getName().startsWith("aop")) {
                        continue;
                    }
                    if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                        continue;
                    }
                    field.setAccessible(true);
                    if (field.getType().equals(JSONObject.class)) {
                        JSONObject v = (JSONObject) field.get(src);
                        if (v != null) {
                            field = getField(dest.getClass(), field.getName());
                            if (field != null && field.getType().equals(JSONObject.class)) {
                                field.set(dest, parseObject(toJSONString(v)));
//                                field.set(dest, JSONObject.parse(v.toJSONString()));
                            }
                        }
                    } else {
                        Object v = field.get(src);
                        if(v != null) {
                            field.set(dest, v);
                        }
                    }
                }catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            clz = clz.getSuperclass();
        }
    }

    public static JSONObject appendString(JSONObject obj, String key, String v) {
        if (obj == null) {
            obj = new JSONObject();
        }
        if (!obj.containsKey(key)) {
            obj.put(key, v);
            return obj;
        }
        String str = obj.getString(key);
        if (str.contains(v)) {
            return obj;
        }
        if (StringUtils.hasText(str)) {
            str = str + ";" + v;
        } else {
            str = v;
        }
        obj.put(key, str);
        return obj;
    }

    public static JSONObject insertString(JSONObject obj, String key, String v) {
        if (obj == null) {
            obj = new JSONObject();
        }
        if (!obj.containsKey(key)) {
            obj.put(key, v);
            return obj;
        }
        String str = obj.getString(key);
        if (str.contains(v)) {
            return obj;
        }
        if (StringUtils.hasText(str)) {
            str = v + ";" + str;
        } else {
            str = v;
        }
        obj.put(key, str);
        return obj;
    }

    public static String getExceptionInfo(Throwable e) {
        StringBuilder sb = new StringBuilder();


        if (e != null) {
            sb.append(getThrowableDetailMsg(e));
            if (e.getCause() != null) {
                sb.append(getThrowableDetailMsg(e.getCause()));
            }
            if (e.getSuppressed() != null) {
                for(Throwable e2: e.getSuppressed()) {
                    sb.append(getThrowableDetailMsg(e2));
                }
            }
        }
        return sb.toString();
    }

    public static String getThrowableDetailMsg(Throwable e) {
        StringBuilder sb = new StringBuilder();

        sb.append(e.getMessage());
        sb.append("\n");
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            sb.append(sw.toString());
        }finally {
            try {
                pw.close();
            }catch (Exception ex) {

            }
            try {
                sw.close();
            }catch (Exception ex) {

            }
        }
        return sb.toString();
    }


    public static JSONObject parseObject(String v) {
        return parseObject(v, false);
    }

    public static JSONObject parseObject(String v, boolean ignoreError) {
        try {
            return JSON.parseObject(v, Feature.AllowUnQuotedFieldNames, Feature.AllowSingleQuotes);
        }catch (Exception ex) {
            ex.printStackTrace();
            if (!ignoreError) {
                throw ex;
            }
            return new JSONObject();
        }
    }

    public static String toJSONString(Object request) {
        return toJSONString(request, false);
    }

    public static String toJSONString(Object request, boolean ignoreError) {
        try {
            String ret = JSON.toJSONString(request, SerializerFeature.DisableCircularReferenceDetect);
            return ret;
        }catch (Exception ex) {
            ex.printStackTrace();
            if (!ignoreError) {
                throw ex;
            }
            return "";
        }
    }

    public static boolean isWindows() {
        try {
            return System.getProperty("os.name").indexOf("Windows") == 0;
        }catch (Exception ex) {

        }
        return false;
    }
    public static boolean isMac() {
        try {
            return System.getProperty("os.name").indexOf("Mac") == 0;
        }catch (Exception ex) {

        }
        return false;
    }
    public static boolean isLinus() {
        try {
            return System.getProperty("os.name").indexOf("Linux") == 0;
        }catch(Exception ex) {

        }
        return false;
    }


    public static String fixPath(String path, boolean checkOS) {
        if (path == null) {
            return null;
        }
        if (!checkOS || !isWindows()) {
            if (StringUtils.hasText(path)) {
                int loop = 0;
                while(loop++ < 100 && path.indexOf("\\") >= 0) {
                    path = path.replace("\\", "/");
                }
            }
        }
        return path;
    }

    public static boolean contains(List<String> ss, String s) {
        if(ss == null || s == null) {
            return false;
        }
        for(String _v:ss) {
            if(s.equals(_v)) {
                return true;
            }
        }
        return false;
    }

    public static IntrospectedColumn getReplaceTableIntrospectedColumn(IntrospectedTable introspectedTable) {
        for(String key: introspectedTable.getParameterColumnsMap().keySet()) {
            if (key.split("\\.").length == 3 && key.split("\\.")[2].equals(introspectedTable.getFullyQualifiedTable().getIntrospectedTableName())) {
                Map<String, List<IntrospectedColumn>> map = introspectedTable.getParameterColumnsMap().get(key);
                for (String k2 : map.keySet()) {
                    if (k2.startsWith("sql.")) {
                        IntrospectedColumn _replaceCol = map.get(k2).get(0);
                        if (_replaceCol.getSqlProjectSet().contains(introspectedTable.getDynProject().getName())) {
                            return _replaceCol;
                        }
                    }
                }
                for (String k2 : map.keySet()) {
                    if (k2.startsWith("sql.")) {
                        IntrospectedColumn _replaceCol = map.get(k2).get(0);
                        if (CollectionUtils.isEmpty(_replaceCol.getSqlProjectSet())) {
                            return _replaceCol;
                        }
                    }
                }
            }
        }
        return null;
    }

    public static List<IntrospectedColumn> getReplaceTableRequestIntrospectedColumn(IntrospectedTable introspectedTable) {
        for(String key: introspectedTable.getParameterColumnsMap().keySet()) {
            if (key.split("\\.").length == 3 && key.split("\\.")[2].equals(introspectedTable.getFullyQualifiedTable().getIntrospectedTableName())) {
                Map<String, List<IntrospectedColumn>> map = introspectedTable.getParameterColumnsMap().get(key);
                for (String k2 : map.keySet()) {
                    if (k2.startsWith("api.request_for_sql.")) {
                        if(CollectionUtils.isEmpty(map.get(k2))) {
                            System.out.println("debugger");
                        } else {
                            IntrospectedColumn _replaceCol = map.get(k2).get(0);
                            if (_replaceCol.getSqlProjectSet().contains(introspectedTable.getDynProject().getName())) {
                                return map.get(k2);
                            }
                        }
                    }
                }
                for (String k2 : map.keySet()) {
                    if (k2.startsWith("api.request_for_sql.")) {
                        if(CollectionUtils.isEmpty(map.get(k2))) {
                            System.out.println("debugger");
                        } else {
                            IntrospectedColumn _replaceCol = map.get(k2).get(0);
                            if (CollectionUtils.isEmpty(_replaceCol.getSqlProjectSet())) {
                                return map.get(k2);
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    public static List<String> getParameterColumnsKeys(IntrospectedTable introspectedTable) {
        List<String> result = new ArrayList<>();
        for(String key: introspectedTable.getParameterColumns().keySet()) {
            if(!CollectionUtils.isEmpty(introspectedTable.getParameterColumns().get(key))) {
                IntrospectedColumn _replaceCol = introspectedTable.getParameterColumns().get(key).get(0);
                if (_replaceCol.getSqlProjectSet().contains(introspectedTable.getDynProject().getName())) {
                    if(!result.contains(key)) {
                        result.add(key);
                    }
                }
                if (CollectionUtils.isEmpty(_replaceCol.getSqlProjectSet())) {
                    if(!result.contains(key)) {
                        result.add(key);
                    }
                }
            }
        }
        return result;
    }

    public static String lineStartWithJavaKeyword(String line) {
        String[] keys = new String[]{"import", "export"};
        for(String k: keys) {
            if(line.startsWith(k+" ")) {
                return k;
            }
        }
        return null;
    }

    public static String getLastToken(String line) {
        try {
            byte[] bytes = line.getBytes("UTF-8");
            int len = bytes.length;
            int pos = len - 1;
            byte[] destBytes = new byte[bytes.length];
            int destPos = 0;
            while (pos >= 0) {
                do {
                    try {
                        byte b = bytes[pos];
                        if(b == '`' || b == ',') {
                            continue;
                        }
                        if(b >= '0' && b <= '9'
                                || b >= 'a' && b <= 'z'
                                || b >= 'A' && b <= 'Z'
                                || b == '`'
                                || b == '_'
                                || b == '$'
                        ) {
                            destBytes[destPos++] = b;
                        } else {
                            pos = 0;
                            break;
                        }
                    }catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }while(false);
                pos--;
            }
            if(destPos > 0) {
                byte[] b2 = new byte[destPos];
                for(int i = 0; i < destPos; i++) {
                    b2[i] = destBytes[destPos - i - 1];
                }
                return new String(b2, "UTF-8");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    public static String isJavaType(String s) {
        if(!StringUtils.hasText(s)) {
            return null;
        }
        String[] types = new String[]{"boolean", "Boolean", "int", "long", "Integer", "Long", "BigDecimal", "double", "float", "Double", "Float", "List<>", "Map<>", "Set<>"};
        for(String t:types) {
            if(s.equals(t)) {
                return s;
            }
        }
        return null;
    }

    public static String getFirstLine(String v) {
        if(v == null) {
            return v;
        }
        List<String> vLines = new ArrayList<>();
        String[] vLines2 = v.split(System.lineSeparator());
        for(String _v: vLines2) {
            if(!StringUtils.hasText(_v)) {
                continue;
            }
            String[] vLines3 = _v.split("\n");
            for(String _v3: vLines3) {
                if(!StringUtils.hasText(_v3)) {
                    continue;
                }
                String[] vLines4 = _v3.split("\r");
                for(String _v4: vLines4) {
                    if(!StringUtils.hasText(_v4)) {
                        continue;
                    }
                    vLines.add(_v4);
                }
            }
        }
        if(!CollectionUtils.isEmpty(vLines)) {
            return vLines.get(0);
        }
        return "";
    }
}
